package fudan.se.project.service.advanced.account.user;


import fudan.se.project.controller.request.ConferenceApplyRequest;
import fudan.se.project.controller.response.BaseResponse;
import fudan.se.project.controller.response.ConferencesGetResponse;
import fudan.se.project.domain.User;
import fudan.se.project.domain.conference.Conference;
import fudan.se.project.domain.conference.Conference.ConferenceStage;
import fudan.se.project.domain.conference.Conference.ConferenceState;
import fudan.se.project.service.infrastructure.entity.conference.ConferenceService;
import fudan.se.project.service.infrastructure.func.account.user.ConferenceApplyService;
import fudan.se.project.util.http.ResponseWrapperUtil;
import fudan.se.project.util.user.UserDetailsUtil;
import lombok.Data;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;

import java.util.Set;

import static fudan.se.project.repository.projection.ConferenceProjection.project;

/**
 * @author X Yang, Gao longchao
 */

@Service
@Data
public class UserActionService {

    private ResponseWrapperUtil responseWrapperUtil;
    private UserDetailsUtil userDetailsUtil;
    private ConferenceService conferenceService;
    private ConferenceApplyService conferenceApplyService;

    public UserActionService(ResponseWrapperUtil responseWrapperUtil,
                             UserDetailsUtil userDetailsUtil,
                             ConferenceService conferenceService,
                             ConferenceApplyService conferenceApplyService
    ) {
        this.responseWrapperUtil = responseWrapperUtil;
        this.userDetailsUtil = userDetailsUtil;

        this.conferenceService = conferenceService;
        this.conferenceApplyService = conferenceApplyService;
    }


    /**
     * Applies a conference and store it in the database.
     *
     * @param request the request passed from UserActionController.
     * @return a responseBody wrapped by ResponseWrapperUtil.
     * @see UserDetailsUtil#currentUser()
     */
    @PreAuthorize("hasAuthority('USER')")
    public ResponseEntity<?> applyConference(ConferenceApplyRequest request) {

        User userChair = userDetailsUtil.currentUser();
        Conference conference = request.toConference();
        Set<String> topicStrings = request.getTopics();

        conferenceApplyService.process(userChair, conference, topicStrings);

        BaseResponse baseResponse = new BaseResponse("conference apply success");
        return responseWrapperUtil.buildResponseBody(baseResponse, HttpStatus.OK);
    }

    @PreAuthorize("hasAuthority('USER')")
    public ResponseEntity<?> getConferencesAsChair(int state, int page) {
        if(state<0||state>2){
            BaseResponse baseResponse=new BaseResponse("arguments error");
            return responseWrapperUtil.buildResponseBody(baseResponse, HttpStatus.NOT_ACCEPTABLE);
        }
        ConferenceState conferenceState = ConferenceState.values()[state];
        User user = userDetailsUtil.currentUser();
        Page<Conference> conferencePage = conferenceService.
                findConferencesAsChairInPage(user, conferenceState, page, 6);
        ConferencesGetResponse conferencesGetResponse = new ConferencesGetResponse(
                conferencePage.getTotalPages(),
                project(conferencePage.getContent()));
        return responseWrapperUtil.buildResponseBody(conferencesGetResponse, HttpStatus.OK);
    }

    @PreAuthorize("hasAuthority('USER')")
    public ResponseEntity<?> getPassedConferencesAsAny(int stage, int page) {
        if(stage<-2||stage>7){
            BaseResponse baseResponse=new BaseResponse("arguments error");
            return responseWrapperUtil.buildResponseBody(baseResponse, HttpStatus.NOT_ACCEPTABLE);
        }
        ConferencesGetResponse conferencesGetResponse;
        Page<Conference> conferencePage;
        User user = userDetailsUtil.currentUser();
        if (stage < 0) {
            conferencePage = conferenceService.findConferencesAsAnyInPage(
                    user,
                    ConferenceState.PASSED,
                    stage,
                    page,
                    6
            );
        } else {
            ConferenceStage conferenceStage = ConferenceStage.values()[stage];
            conferencePage = conferenceService.findConferencesAsAnyInPage(
                    user,
                    ConferenceState.PASSED,
                    conferenceStage,
                    page,
                    6
            );
        }
        conferencesGetResponse = new ConferencesGetResponse(
                conferencePage.getTotalPages(),
                project(conferencePage.getContent()));
        conferencesGetResponse.setMessage("success");

        return responseWrapperUtil.buildResponseBody(conferencesGetResponse, HttpStatus.OK);

    }

    @PreAuthorize("hasAuthority('USER')")
    public ResponseEntity<?> getAllPassedConferences(int stage, int page) {
        ConferencesGetResponse conferencesGetResponse;
        Page<Conference> conferencePage;
        if (stage < 0) {
            conferencePage = conferenceService.findAllConferencesInPage(
                    ConferenceState.PASSED,
                    stage,
                    page,
                    6);
        } else {
            ConferenceStage conferenceStage = ConferenceStage.values()[stage];
            conferencePage = conferenceService.findAllConferencesInPage(
                    ConferenceState.PASSED,
                    conferenceStage,
                    page,
                    6
            );
        }
        conferencesGetResponse = new ConferencesGetResponse(
                conferencePage.getTotalPages(),
                project(conferencePage.getContent()));
        conferencesGetResponse.setMessage("success");

        return responseWrapperUtil.buildResponseBody(conferencesGetResponse, HttpStatus.OK);
    }
}
